package com.atguigu.schedule.service;

import com.atguigu.schedule.common.Result;
import com.atguigu.schedule.pojo.SlamSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import jakarta.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * SLAM服务管理器
 * 负责管理SLAM建图进程和数据处理
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SlamService {
    
    // private final StreamFrameService streamFrameService;
    
    @Value("${slam.vocabulary.path:/opt/smart-care-car/slam/ORB_SLAM2/Vocabulary/ORBvoc.txt}")
    private String vocabularyPath;
    
    @Value("${slam.camera.params:/opt/smart-care-car/slam/ORB_SLAM2/test.yaml}")
    private String cameraParamsPath;
    
    @Value("${slam.output.directory:/opt/smart-care-car/slam/output}")
    private String outputDirectory;
    
    @Value("${slam.executable.path:/opt/smart-care-car/slam/ORB_SLAM2/test}")
    private String slamExecutablePath;
    
    // 存储活跃的SLAM进程
    private final Map<Long, Process> activeProcesses = new ConcurrentHashMap<>();
    
    // 存储会话状态
    private final Map<Long, SlamSession.SessionStatus> sessionStatuses = new ConcurrentHashMap<>();
    
    // 存储实时轨迹数据
    private final Map<Long, List<Map<String, Object>>> realtimeTrajectories = new ConcurrentHashMap<>();
    
    // JSON解析器
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    
    /**
     * 启动SLAM建图会话（增强版）
     */
    public CompletableFuture<SlamSession> startSlamSession(SlamSession session) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                log.info("🚀 启动增强版SLAM建图会话: {}", session.getSessionName());
                
                // 更新会话状态为启动中
                session.setStatus(SlamSession.SessionStatus.STARTING);
                session.setStartedAt(LocalDateTime.now());
                sessionStatuses.put(session.getId(), session.getStatus());
                
                // 准备输出目录
                Path outputPath = Paths.get(outputDirectory, session.getSessionName());
                Files.createDirectories(outputPath);
                
                // 构建增强版SLAM命令
                List<String> command = buildEnhancedSlamCommand(session, outputPath.toString());
                log.info("📋 增强版SLAM命令: {}", String.join(" ", command));
                
                // 启动增强版SLAM进程
                ProcessBuilder processBuilder = new ProcessBuilder(command);
                processBuilder.directory(new File("/opt/smart-care-car"));
                processBuilder.redirectErrorStream(true);
                
                Process process = processBuilder.start();
                activeProcesses.put(session.getId(), process);
                
                // 更新状态为运行中
                session.setStatus(SlamSession.SessionStatus.RUNNING);
                sessionStatuses.put(session.getId(), session.getStatus());
                
                // 启动增强版监控线程
                startEnhancedMonitoringThread(session.getId(), process);
                
                log.info("✅ 增强版SLAM建图会话启动成功: {}", session.getSessionName());
                return session;
                
            } catch (Exception e) {
                log.error("❌ 启动增强版SLAM建图会话失败: {}", session.getSessionName(), e);
                session.setStatus(SlamSession.SessionStatus.ERROR);
                session.setErrorMessage(e.getMessage());
                session.setEndedAt(LocalDateTime.now());
                sessionStatuses.put(session.getId(), session.getStatus());
                throw new RuntimeException("启动增强版SLAM会话失败: " + e.getMessage(), e);
            }
        });
    }
    
    /**
     * 停止SLAM建图会话
     */
    public CompletableFuture<Boolean> stopSlamSession(Long sessionId) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                log.info("🛑 停止SLAM建图会话: {}", sessionId);
                
                Process process = activeProcesses.get(sessionId);
                if (process != null && process.isAlive()) {
                    process.destroy();
                    // 等待进程结束
                    boolean terminated = process.waitFor(10, java.util.concurrent.TimeUnit.SECONDS);
                    if (!terminated) {
                        process.destroyForcibly();
                    }
                }
                
                activeProcesses.remove(sessionId);
                sessionStatuses.put(sessionId, SlamSession.SessionStatus.STOPPED);
                realtimeTrajectories.remove(sessionId);
                
                log.info("✅ SLAM建图会话已停止: {}", sessionId);
                return true;
                
            } catch (Exception e) {
                log.error("❌ 停止SLAM建图会话失败: {}", sessionId, e);
                return false;
            }
        });
    }
    
    /**
     * 暂停SLAM建图会话
     */
    public CompletableFuture<Boolean> pauseSlamSession(Long sessionId) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                log.info("⏸️ 暂停SLAM建图会话: {}", sessionId);
                
                Process process = activeProcesses.get(sessionId);
                if (process != null && process.isAlive()) {
                    // 发送SIGSTOP信号暂停进程
                    Runtime.getRuntime().exec("kill -STOP " + process.pid());
                    sessionStatuses.put(sessionId, SlamSession.SessionStatus.PAUSED);
                    log.info("✅ SLAM建图会话已暂停: {}", sessionId);
                    return true;
                }
                
                return false;
                
            } catch (Exception e) {
                log.error("❌ 暂停SLAM建图会话失败: {}", sessionId, e);
                return false;
            }
        });
    }
    
    /**
     * 恢复SLAM建图会话
     */
    public CompletableFuture<Boolean> resumeSlamSession(Long sessionId) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                log.info("▶️ 恢复SLAM建图会话: {}", sessionId);
                
                Process process = activeProcesses.get(sessionId);
                if (process != null && process.isAlive()) {
                    // 发送SIGCONT信号恢复进程
                    Runtime.getRuntime().exec("kill -CONT " + process.pid());
                    sessionStatuses.put(sessionId, SlamSession.SessionStatus.RUNNING);
                    log.info("✅ SLAM建图会话已恢复: {}", sessionId);
                    return true;
                }
                
                return false;
                
            } catch (Exception e) {
                log.error("❌ 恢复SLAM建图会话失败: {}", sessionId, e);
                return false;
            }
        });
    }
    
    /**
     * 获取会话状态
     */
    public SlamSession.SessionStatus getSessionStatus(Long sessionId) {
        return sessionStatuses.getOrDefault(sessionId, SlamSession.SessionStatus.STOPPED);
    }
    
    /**
     * 获取实时轨迹数据
     */
    public List<Map<String, Object>> getRealtimeTrajectory(Long sessionId) {
        return realtimeTrajectories.getOrDefault(sessionId, new ArrayList<>());
    }
    
    /**
     * 获取活跃会话列表
     */
    public Set<Long> getActiveSessionIds() {
        return activeProcesses.keySet();
    }
    
    /**
     * 构建SLAM命令
     */
    private List<String> buildSlamCommand(SlamSession session, String outputPath) {
        List<String> command = new ArrayList<>();
        command.add(slamExecutablePath);
        command.add(vocabularyPath);
        command.add(cameraParamsPath);
        command.add(session.getVideoSource());
        
        return command;
    }
    
    /**
     * 启动监控线程
     */
    private void startMonitoringThread(Long sessionId, Process process) {
        CompletableFuture.runAsync(() -> {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    log.debug("SLAM输出 [{}]: {}", sessionId, line);
                    
                    // 解析SLAM输出，提取轨迹信息
                    parseSlamOutput(sessionId, line);
                }
                
                // 进程结束
                int exitCode = process.waitFor();
                log.info("SLAM进程结束 [{}]: 退出码 {}", sessionId, exitCode);
                
                if (exitCode == 0) {
                    sessionStatuses.put(sessionId, SlamSession.SessionStatus.STOPPED);
                } else {
                    sessionStatuses.put(sessionId, SlamSession.SessionStatus.ERROR);
                }
                
            } catch (Exception e) {
                log.error("监控SLAM进程失败 [{}]", sessionId, e);
                sessionStatuses.put(sessionId, SlamSession.SessionStatus.ERROR);
            } finally {
                activeProcesses.remove(sessionId);
            }
        });
    }
    
    /**
     * 解析SLAM输出
     */
    private void parseSlamOutput(Long sessionId, String output) {
        // 这里可以根据SLAM的实际输出格式来解析轨迹数据
        // 示例：解析关键帧信息
        if (output.contains("KeyFrame") || output.contains("MapPoint")) {
            Map<String, Object> frameData = new HashMap<>();
            frameData.put("timestamp", System.currentTimeMillis());
            frameData.put("data", output);
            
            realtimeTrajectories.computeIfAbsent(sessionId, k -> new ArrayList<>()).add(frameData);
        }
    }
    
    /**
     * 使用帧文件启动SLAM
     */
    private void startSlamWithFrames(SlamSession session, String captureSessionId) {
        try {
            // 创建帧处理脚本
            String scriptPath = createFrameProcessingScript(session, captureSessionId);
            
            // 构建SLAM命令
            List<String> command = Arrays.asList(
                "bash", scriptPath
            );
            
            log.info("📋 SLAM帧处理命令: {}", String.join(" ", command));
            
            // 启动SLAM进程
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            processBuilder.directory(new File("/opt/smart-care-car/slam/ORB_SLAM2"));
            processBuilder.redirectErrorStream(true);
            
            Process process = processBuilder.start();
            activeProcesses.put(session.getId(), process);
            
            // 启动监控线程
            startMonitoringThread(session.getId(), process);
            
        } catch (Exception e) {
            log.error("启动SLAM帧处理失败", e);
            throw new RuntimeException("启动SLAM帧处理失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 创建帧处理脚本
     */
    private String createFrameProcessingScript(SlamSession session, String captureSessionId) throws IOException {
        String scriptPath = "/tmp/slam_frame_processor_" + session.getId() + ".sh";
        
        StringBuilder script = new StringBuilder();
        script.append("#!/bin/bash\n");
        script.append("set -e\n\n");
        
        script.append("# SLAM帧处理脚本\n");
        script.append("SESSION_ID=\"").append(session.getId()).append("\"\n");
        script.append("CAPTURE_SESSION_ID=\"").append(captureSessionId).append("\"\n");
        script.append("VOCABULARY=\"").append(vocabularyPath).append("\"\n");
        script.append("CAMERA_PARAMS=\"").append(cameraParamsPath).append("\"\n");
        script.append("OUTPUT_DIR=\"").append(outputDirectory).append("/").append(session.getSessionName()).append("\"\n");
        script.append("FRAME_DIR=\"").append(outputDirectory).append("/").append(captureSessionId).append("\"\n\n");
        
        script.append("echo \"🚀 启动SLAM帧处理: $SESSION_ID\"\n");
        script.append("echo \"📁 帧目录: $FRAME_DIR\"\n");
        script.append("echo \"📁 输出目录: $OUTPUT_DIR\"\n\n");
        
        script.append("# 等待帧文件生成\n");
        script.append("echo \"⏳ 等待帧文件生成...\"\n");
        script.append("while [ ! -d \"$FRAME_DIR\" ] || [ -z \"$(ls -A $FRAME_DIR 2>/dev/null)\" ]; do\n");
        script.append("    sleep 1\n");
        script.append("done\n\n");
        
        script.append("# 创建输出目录\n");
        script.append("mkdir -p \"$OUTPUT_DIR\"\n\n");
        
        script.append("# 启动SLAM处理循环\n");
        script.append("echo \"🎯 开始SLAM处理...\"\n");
        script.append("FRAME_COUNT=0\n");
        script.append("while true; do\n");
        script.append("    # 获取最新帧文件\n");
        script.append("    LATEST_FRAME=$(ls -t \"$FRAME_DIR\"/frame_*.jpg 2>/dev/null | head -1)\n");
        script.append("    \n");
        script.append("    if [ -n \"$LATEST_FRAME\" ]; then\n");
        script.append("        echo \"📸 处理帧: $LATEST_FRAME\"\n");
        script.append("        \n");
        script.append("        # 调用SLAM处理（这里需要根据实际的SLAM接口调整）\n");
        script.append("        # 示例：使用OpenCV或其他图像处理库\n");
        script.append("        \n");
        script.append("        FRAME_COUNT=$((FRAME_COUNT + 1))\n");
        script.append("        echo \"📊 已处理帧数: $FRAME_COUNT\"\n");
        script.append("    fi\n");
        script.append("    \n");
        script.append("    sleep 0.1  # 100ms间隔\n");
        script.append("done\n");
        
        // 写入脚本文件
        Files.write(Paths.get(scriptPath), script.toString().getBytes());
        
        // 设置执行权限
        ProcessBuilder chmod = new ProcessBuilder("chmod", "+x", scriptPath);
        try {
            chmod.start().waitFor();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("设置脚本执行权限失败", e);
        }
        
        return scriptPath;
    }
    
    /**
     * 检查SLAM环境
     */
    public Map<String, Object> checkSlamEnvironment() {
        Map<String, Object> result = new HashMap<>();
        
        // 检查可执行文件
        File executable = new File(slamExecutablePath);
        result.put("executableExists", executable.exists());
        result.put("executablePath", slamExecutablePath);
        
        // 检查词汇表文件
        File vocabulary = new File(vocabularyPath);
        result.put("vocabularyExists", vocabulary.exists());
        result.put("vocabularyPath", vocabularyPath);
        
        // 检查相机参数文件
        File cameraParams = new File(cameraParamsPath);
        result.put("cameraParamsExists", cameraParams.exists());
        result.put("cameraParamsPath", cameraParamsPath);
        
        // 检查输出目录
        File outputDir = new File(outputDirectory);
        result.put("outputDirectoryExists", outputDir.exists());
        result.put("outputDirectoryPath", outputDirectory);
        
        return result;
    }
    
    
    /**
     * 启动WebRTC SLAM建图会话
     */
    public CompletableFuture<SlamSession> startWebRTCSlamSession(SlamSession session) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                log.info("🚀 启动WebRTC SLAM建图会话: {}", session.getSessionName());
                
                // 更新会话状态为启动中
                session.setStatus(SlamSession.SessionStatus.STARTING);
                session.setStartedAt(LocalDateTime.now());
                sessionStatuses.put(session.getId(), session.getStatus());
                
                // 准备输出目录
                Path outputPath = Paths.get(outputDirectory, session.getSessionName());
                Files.createDirectories(outputPath);
                
                // 构建WebRTC SLAM命令
                List<String> command = buildWebRTCSlamCommand(session, outputPath.toString());
                log.info("📋 WebRTC SLAM命令: {}", String.join(" ", command));
                
                // 启动WebRTC SLAM进程
                ProcessBuilder processBuilder = new ProcessBuilder(command);
                processBuilder.directory(new File("/opt/smart-care-car/slam"));
                processBuilder.redirectErrorStream(true);
                
                Process process = processBuilder.start();
                activeProcesses.put(session.getId(), process);
                
                // 更新状态为运行中
                session.setStatus(SlamSession.SessionStatus.RUNNING);
                sessionStatuses.put(session.getId(), session.getStatus());
                
                // 启动WebRTC监控线程
                startWebRTCMonitoringThread(session.getId(), process);
                
                log.info("✅ WebRTC SLAM建图会话启动成功: {}", session.getSessionName());
                return session;
                
            } catch (Exception e) {
                log.error("❌ 启动WebRTC SLAM建图会话失败: {}", session.getSessionName(), e);
                session.setStatus(SlamSession.SessionStatus.ERROR);
                session.setErrorMessage(e.getMessage());
                session.setEndedAt(LocalDateTime.now());
                sessionStatuses.put(session.getId(), session.getStatus());
                throw new RuntimeException("启动WebRTC SLAM会话失败: " + e.getMessage(), e);
            }
        });
    }
    
    /**
     * 构建增强版SLAM命令（WebRTC模式）
     */
    private List<String> buildEnhancedSlamCommand(SlamSession session, String outputPath) {
        List<String> command = new ArrayList<>();
        command.add("python3");
        command.add("/opt/smart-care-car/slam/frontend_stream_processor.py"); // 使用前端流处理器
        
        return command;
    }
    
    /**
     * 构建WebRTC SLAM命令
     */
    private List<String> buildWebRTCSlamCommand(SlamSession session, String outputPath) {
        List<String> command = new ArrayList<>();
        command.add("python3");
        command.add("/opt/smart-care-car/slam/frontend_stream_processor.py"); // 使用前端流处理器
        
        return command;
    }
    
    /**
     * 启动增强版监控线程
     */
    private void startEnhancedMonitoringThread(Long sessionId, Process process) {
        CompletableFuture.runAsync(() -> {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    log.debug("增强版SLAM输出 [{}]: {}", sessionId, line);
                    
                    // 解析增强版SLAM输出，提取3D轨迹信息
                    parseEnhancedSlamOutput(sessionId, line);
                }
            } catch (Exception e) {
                log.error("❌ 增强版SLAM监控线程错误 [{}]: {}", sessionId, e.getMessage());
            }
        });
    }
    
    /**
     * 启动WebRTC监控线程
     */
    private void startWebRTCMonitoringThread(Long sessionId, Process process) {
        CompletableFuture.runAsync(() -> {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    log.debug("WebRTC SLAM输出 [{}]: {}", sessionId, line);
                    
                    // 解析WebRTC SLAM输出，提取实时轨迹信息
                    parseWebRTCSlamOutput(sessionId, line);
                }
            } catch (Exception e) {
                log.error("❌ WebRTC SLAM监控线程错误 [{}]: {}", sessionId, e.getMessage());
            }
        });
    }
    
    /**
     * 解析增强版SLAM输出
     */
    private void parseEnhancedSlamOutput(Long sessionId, String line) {
        try {
            // 解析增强版SLAM的JSON输出
            if (line.contains("position_3d") && line.contains("pose_matrix")) {
                // 这里可以解析JSON格式的轨迹数据
                // 实际实现需要根据enhanced_slam_processor.py的输出格式调整
                log.debug("解析增强版SLAM轨迹数据 [{}]: {}", sessionId, line);
            }
        } catch (Exception e) {
            log.warn("解析增强版SLAM输出失败 [{}]: {}", sessionId, e.getMessage());
        }
    }
    
    /**
     * 解析WebRTC SLAM输出
     */
    private void parseWebRTCSlamOutput(Long sessionId, String line) {
        try {
            // 解析WebRTC SLAM的实时输出
            if (line.contains("帧:") && line.contains("关键帧:") && line.contains("地图点:")) {
                // 解析实时统计信息
                log.debug("解析WebRTC SLAM统计 [{}]: {}", sessionId, line);
            }
        } catch (Exception e) {
            log.warn("解析WebRTC SLAM输出失败 [{}]: {}", sessionId, e.getMessage());
        }
    }
    
    /**
     * 获取SLAM实时数据
     */
    public Result<Map<String, Object>> getRealtimeSlamData(Long sessionId) {
        try {
            log.info("📊 获取SLAM实时数据，会话ID: {}", sessionId);
            
            // 尝试多个可能的数据文件路径
            String[] possibleFiles = {
                String.format("%s/realtime_optimized_slam_%d.json", outputDirectory, sessionId),
                String.format("%s/visual_slam_test/realtime_optimized_slam_%d.json", outputDirectory, sessionId),
                String.format("%s/realtime_webrtc_slam_%d.json", outputDirectory, sessionId),
                String.format("%s/realtime_visual_slam_%d.json", outputDirectory, sessionId),
                String.format("%s/visual_slam_test/realtime_visual_slam_%d.json", outputDirectory, sessionId)
            };
            
            Path filePath = null;
            for (String file : possibleFiles) {
                Path path = Paths.get(file);
                if (Files.exists(path)) {
                    filePath = path;
                    break;
                }
            }
            
            if (filePath == null) {
                return Result.build(null, 404, "实时数据文件不存在");
            }
            
            // 读取JSON数据
            String jsonContent = Files.readString(filePath);
            Map<String, Object> slamData = new HashMap<>();
            
            try {
                // 尝试解析完整的JSON数据
                slamData = objectMapper.readValue(jsonContent, Map.class);
            } catch (Exception e) {
                // 如果解析失败，使用简化版本
                slamData.put("session_id", sessionId);
                slamData.put("status", sessionStatuses.getOrDefault(sessionId, SlamSession.SessionStatus.STOPPED).toString());
                slamData.put("is_running", activeProcesses.containsKey(sessionId));
            }
            
            // 添加文件信息
            slamData.put("data_file", filePath.toString());
            slamData.put("file_size", Files.size(filePath));
            slamData.put("last_modified", Files.getLastModifiedTime(filePath).toString());
            
            return Result.build(slamData, 200, "获取实时数据成功");
            
        } catch (Exception e) {
            log.error("❌ 获取SLAM实时数据失败", e);
            return Result.build(null, 500, "获取实时数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取SLAM轨迹数据
     */
    public Result<Map<String, Object>> getSlamTrajectory(Long sessionId) {
        try {
            log.info("🗺️ 获取SLAM轨迹数据，会话ID: {}", sessionId);
            
            // 检查会话是否存在
            if (!sessionStatuses.containsKey(sessionId)) {
                return Result.build(null, 404, "会话不存在");
            }
            
            // 读取轨迹数据文件
            String trajectoryFile = String.format("%s/webrtc_slam_trajectory_%d.json", outputDirectory, sessionId);
            Path filePath = Paths.get(trajectoryFile);
            
            if (!Files.exists(filePath)) {
                return Result.build(null, 404, "轨迹数据文件不存在");
            }
            
            // 读取JSON数据
            String jsonContent = Files.readString(filePath);
            Map<String, Object> trajectoryData = new HashMap<>();
            
            // 解析JSON（简化版本）
            trajectoryData.put("session_id", sessionId);
            trajectoryData.put("file_path", trajectoryFile);
            trajectoryData.put("file_size", Files.size(filePath));
            trajectoryData.put("last_modified", Files.getLastModifiedTime(filePath).toString());
            
            return Result.build(trajectoryData, 200, "获取轨迹数据成功");
            
        } catch (Exception e) {
            log.error("❌ 获取SLAM轨迹数据失败", e);
            return Result.build(null, 500, "获取轨迹数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取SLAM关键帧数据
     */
    public Result<Map<String, Object>> getSlamKeyframes(Long sessionId) {
        try {
            log.info("🔑 获取SLAM关键帧数据，会话ID: {}", sessionId);
            
            // 检查会话是否存在
            if (!sessionStatuses.containsKey(sessionId)) {
                return Result.build(null, 404, "会话不存在");
            }
            
            // 读取关键帧数据文件
            String keyframesFile = String.format("%s/webrtc_slam_trajectory_%d.json", outputDirectory, sessionId);
            Path filePath = Paths.get(keyframesFile);
            
            if (!Files.exists(filePath)) {
                return Result.build(null, 404, "关键帧数据文件不存在");
            }
            
            // 读取JSON数据
            String jsonContent = Files.readString(filePath);
            Map<String, Object> keyframesData = new HashMap<>();
            
            // 解析JSON（简化版本）
            keyframesData.put("session_id", sessionId);
            keyframesData.put("file_path", keyframesFile);
            keyframesData.put("file_size", Files.size(filePath));
            keyframesData.put("last_modified", Files.getLastModifiedTime(filePath).toString());
            
            return Result.build(keyframesData, 200, "获取关键帧数据成功");
            
        } catch (Exception e) {
            log.error("❌ 获取SLAM关键帧数据失败", e);
            return Result.build(null, 500, "获取关键帧数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 获取SLAM地图点数据
     */
    public Result<Map<String, Object>> getSlamMapPoints(Long sessionId) {
        try {
            log.info("🗺️ 获取SLAM地图点数据，会话ID: {}", sessionId);
            
            // 检查会话是否存在
            if (!sessionStatuses.containsKey(sessionId)) {
                return Result.build(null, 404, "会话不存在");
            }
            
            // 读取地图点数据文件
            String mapPointsFile = String.format("%s/webrtc_slam_trajectory_%d.json", outputDirectory, sessionId);
            Path filePath = Paths.get(mapPointsFile);
            
            if (!Files.exists(filePath)) {
                return Result.build(null, 404, "地图点数据文件不存在");
            }
            
            // 读取JSON数据
            String jsonContent = Files.readString(filePath);
            Map<String, Object> mapPointsData = new HashMap<>();
            
            // 解析JSON（简化版本）
            mapPointsData.put("session_id", sessionId);
            mapPointsData.put("file_path", mapPointsFile);
            mapPointsData.put("file_size", Files.size(filePath));
            mapPointsData.put("last_modified", Files.getLastModifiedTime(filePath).toString());
            
            return Result.build(mapPointsData, 200, "获取地图点数据成功");
            
        } catch (Exception e) {
            log.error("❌ 获取SLAM地图点数据失败", e);
            return Result.build(null, 500, "获取地图点数据失败: " + e.getMessage());
        }
    }
    
    /**
     * 查看SLAM图片
     */
    public void viewImages(String type, Long sessionId, HttpServletResponse response) throws IOException {
        try {
            // 构建图片目录路径
            String baseDir = outputDirectory + "/visual_slam_test";
            String imageDir;
            
            switch (type) {
                case "original":
                    imageDir = baseDir + "/frames";
                    break;
                case "keypoints":
                    imageDir = baseDir + "/frames";
                    break;
                case "keyframes":
                    imageDir = baseDir + "/keyframes";
                    break;
                case "analysis":
                    imageDir = baseDir + "/keyframes";
                    break;
                default:
                    throw new IllegalArgumentException("不支持的图片类型: " + type);
            }
            
            // 检查目录是否存在
            Path dirPath = Paths.get(imageDir);
            if (!Files.exists(dirPath)) {
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                response.getWriter().write("图片目录不存在: " + imageDir);
                return;
            }
            
            // 获取图片文件列表
            List<Path> imageFiles = Files.list(dirPath)
                .filter(path -> {
                    String fileName = path.getFileName().toString().toLowerCase();
                    if ("original".equals(type)) {
                        return fileName.startsWith("frame_") && fileName.endsWith(".jpg");
                    } else if ("keypoints".equals(type)) {
                        return fileName.startsWith("keypoints_") && fileName.endsWith(".jpg");
                    } else if ("keyframes".equals(type)) {
                        return fileName.endsWith(".jpg") && !fileName.contains("_analysis");
                    } else if ("analysis".equals(type)) {
                        return fileName.endsWith("_analysis.jpg");
                    }
                    return false;
                })
                .sorted()
                .collect(Collectors.toList());
            
            if (imageFiles.isEmpty()) {
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                response.getWriter().write("未找到指定类型的图片文件");
                return;
            }
            
            // 生成HTML页面
            StringBuilder html = new StringBuilder();
            html.append("<!DOCTYPE html>");
            html.append("<html><head>");
            html.append("<title>SLAM图片查看器 - ").append(type).append("</title>");
            html.append("<meta charset='UTF-8'>");
            html.append("<style>");
            html.append("body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }");
            html.append(".header { background: white; padding: 20px; border-radius: 10px; margin-bottom: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }");
            html.append(".gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }");
            html.append(".image-card { background: white; border-radius: 10px; padding: 15px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }");
            html.append(".image-card img { width: 100%; height: 200px; object-fit: cover; border-radius: 5px; }");
            html.append(".image-info { margin-top: 10px; font-size: 14px; color: #666; }");
            html.append(".stats { background: #e3f2fd; padding: 15px; border-radius: 5px; margin-bottom: 20px; }");
            html.append("</style>");
            html.append("</head><body>");
            
            // 页面头部
            html.append("<div class='header'>");
            html.append("<h1>🖼️ SLAM图片查看器</h1>");
            html.append("<p><strong>类型:</strong> ").append(getTypeDescription(type)).append("</p>");
            html.append("<p><strong>会话ID:</strong> ").append(sessionId).append("</p>");
            html.append("<p><strong>图片数量:</strong> ").append(imageFiles.size()).append(" 张</p>");
            html.append("<p><strong>目录:</strong> ").append(imageDir).append("</p>");
            html.append("</div>");
            
            // 图片网格
            html.append("<div class='gallery'>");
            for (Path imageFile : imageFiles) {
                String fileName = imageFile.getFileName().toString();
                String relativePath = imageDir.replace(outputDirectory, "") + "/" + fileName;
                
                html.append("<div class='image-card'>");
                html.append("<img src='").append(relativePath).append("' alt='").append(fileName).append("'>");
                html.append("<div class='image-info'>");
                html.append("<p><strong>文件名:</strong> ").append(fileName).append("</p>");
                try {
                    long fileSize = Files.size(imageFile);
                    html.append("<p><strong>大小:</strong> ").append(formatFileSize(fileSize)).append("</p>");
                } catch (Exception e) {
                    html.append("<p><strong>大小:</strong> 未知</p>");
                }
                html.append("</div>");
                html.append("</div>");
            }
            html.append("</div>");
            
            html.append("</body></html>");
            
            // 设置响应
            response.setContentType("text/html;charset=UTF-8");
            response.getWriter().write(html.toString());
            
        } catch (Exception e) {
            log.error("❌ 查看SLAM图片失败", e);
            throw new IOException("查看图片失败: " + e.getMessage(), e);
        }
    }
    
    private String getTypeDescription(String type) {
        switch (type) {
            case "original": return "原始视频帧";
            case "keypoints": return "关键点检测帧";
            case "keyframes": return "SLAM关键帧";
            case "analysis": return "关键帧分析图";
            default: return "未知类型";
        }
    }
    
    private String formatFileSize(long bytes) {
        if (bytes < 1024) return bytes + " B";
        if (bytes < 1024 * 1024) return String.format("%.1f KB", bytes / 1024.0);
        if (bytes < 1024 * 1024 * 1024) return String.format("%.1f MB", bytes / (1024.0 * 1024.0));
        return String.format("%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0));
    }
}
